<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>星火RAG数据集创建工具</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 样式保持不变 */
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
            color: #333;
        }

        .container {
            background-color: rgba(255, 255, 255, 0.97);
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
            width: 100%;
            max-width: 700px;
            overflow: hidden;
        }

        .header {
            background: linear-gradient(to right, #1a2a6c, #b21f1f);
            color: white;
            padding: 25px 30px;
            text-align: center;
        }

        .header h1 {
            font-weight: 600;
            margin-bottom: 10px;
            font-size: 28px;
        }

        .header p {
            opacity: 0.9;
            font-size: 16px;
        }

        .content {
            padding: 30px;
        }

        .form-group {
            margin-bottom: 25px;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 500;
            color: #1a2a6c;
            font-size: 16px;
        }

        input {
            width: 100%;
            padding: 14px;
            border: 2px solid #ddd;
            border-radius: 8px;
            font-size: 16px;
            transition: border-color 0.3s;
        }

        input:focus {
            border-color: #1a2a6c;
            outline: none;
            box-shadow: 0 0 0 3px rgba(26, 42, 108, 0.2);
        }

        .input-with-icon {
            position: relative;
        }

        .input-with-icon i {
            position: absolute;
            right: 15px;
            top: 50%;
            transform: translateY(-50%);
            color: #6c757d;
            cursor: pointer;
        }

        .dataset-name-group {
            display: flex;
            gap: 15px;
        }

        .dataset-name-group input {
            flex: 1;
        }

        button {
            background: linear-gradient(to right, #1a2a6c, #b21f1f);
            color: white;
            border: none;
            padding: 16px 25px;
            font-size: 18px;
            border-radius: 8px;
            cursor: pointer;
            width: 100%;
            font-weight: 600;
            letter-spacing: 1px;
            transition: transform 0.2s, box-shadow 0.2s;
            margin-top: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 10px;
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        button:active {
            transform: translateY(0);
        }

        .result-container {
            margin-top: 30px;
            padding: 25px;
            background-color: #f8f9fa;
            border-radius: 8px;
            border-left: 5px solid #1a2a6c;
            display: none;
        }

        .result-title {
            font-weight: 600;
            color: #1a2a6c;
            margin-bottom: 15px;
            font-size: 20px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        #dataset-id {
            font-size: 24px;
            font-weight: 700;
            color: #b21f1f;
            word-break: break-all;
            padding: 15px;
            background-color: #f1f3f4;
            border-radius: 8px;
            margin: 15px 0;
        }

        .loading {
            display: none;
            text-align: center;
            margin: 20px 0;
            flex-direction: column;
            align-items: center;
        }

        .spinner {
            border: 4px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top: 4px solid #1a2a6c;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin-bottom: 15px;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .error {
            color: #dc3545;
            background-color: #f8d7da;
            padding: 15px;
            border-radius: 8px;
            margin-top: 15px;
            display: none;
            border-left: 4px solid #dc3545;
        }

        .info {
            background-color: #e9f7fe;
            padding: 20px;
            border-radius: 8px;
            margin-bottom: 25px;
            color: #0c5460;
            border-left: 4px solid #1a2a6c;
        }

        .info h3 {
            margin-bottom: 15px;
            color: #1a2a6c;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .info ul {
            padding-left: 20px;
        }

        .info li {
            margin-bottom: 10px;
            line-height: 1.5;
        }

        .timestamp {
            font-size: 14px;
            color: #6c757d;
            margin-top: 10px;
        }

        .success-check {
            color: #28a745;
            font-size: 24px;
        }

        .code-example {
            background-color: #2d2d2d;
            color: #f8f9fa;
            padding: 15px;
            border-radius: 8px;
            margin-top: 20px;
            font-family: 'Courier New', monospace;
            overflow-x: auto;
            font-size: 14px;
        }

        .copy-btn {
            background: #6c757d;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            margin-top: 10px;
            display: inline-flex;
            align-items: center;
            gap: 5px;
        }

        .copy-btn:hover {
            background: #5a6268;
        }

        @media (max-width: 600px) {
            .header h1 {
                font-size: 24px;
            }

            .content {
                padding: 20px;
            }

            .dataset-name-group {
                flex-direction: column;
                gap: 15px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1><i class="fas fa-database"></i> 星火RAG数据集创建工具</h1>
            <p>创建您的RAG数据集</p>
        </div>

        <div class="content">
            <div class="info">
                <h3><i class="fas fa-info-circle"></i> 使用说明</h3>
                <ul>
                    <li>在<a href="https://console.xfyun.cn/app/myapp" target="_blank">讯飞开放平台官网</a>创建新应用</li>
                    <li>在星火认知大模型-星火知识库中购买能力</li>
                    <li>在下方输入您的星火知识库API凭证和数据集名称</li>
                    <li>点击"创建数据集"按钮生成新的数据集</li>
                    <li>生成的Dataset ID将显示在页面下方</li>
                    <li>此Dataset ID可用于后续的星辰RAG操作</li>
                </ul>
            </div>

            <div class="form-group">
                <label for="app-id">APPID</label>
                <input type="text" id="app-id" placeholder="请输入您的APPID">
            </div>

            <div class="form-group">
                <label for="api-secret">APISecret</label>
                <div class="input-with-icon">
                    <input type="password" id="api-secret" placeholder="请输入您的APISecret">
                    <i class="fas fa-eye" id="toggle-secret"></i>
                </div>
            </div>

            <div class="form-group">
                <label for="dataset-name">数据集名称</label>
                <div class="dataset-name-group">
                    <input type="text" id="dataset-name" placeholder="请输入数据集名称" value="我的数据集">
                </div>
            </div>

            <button id="create-btn">
                <i class="fas fa-plus-circle"></i> 创建数据集
            </button>

            <div class="loading" id="loading">
                <div class="spinner"></div>
                <p>正在创建数据集，请稍候...</p>
            </div>

            <div class="error" id="error-message"></div>

            <div class="result-container" id="result-container">
                <div class="result-title">
                    <i class="fas fa-check-circle success-check"></i> 数据集创建成功！
                </div>
                <p>您的Dataset ID:</p>
                <div id="dataset-id"></div>
                <div class="timestamp" id="timestamp"></div>

                <div class="code-example">
                    <p>// 后续API调用可使用此ID</p>
                    <p>const datasetId = "<span id="code-dataset-id"></span>";</p>
                </div>
                <button class="copy-btn" id="copy-btn">
                    <i class="fas fa-copy"></i> 复制Dataset ID
                </button>
            </div>
        </div>
    </div>

    <script>
        // 简化的MD5实现
        function md5(inputString) {
            function rotateLeft(lValue, iShiftBits) {
                return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
            }

            function addUnsigned(lX, lY) {
                var lX4, lY4, lX8, lY8, lResult;
                lX8 = (lX & 0x80000000);
                lY8 = (lY & 0x80000000);
                lX4 = (lX & 0x40000000);
                lY4 = (lY & 0x40000000);
                lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
                if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
                if (lX4 | lY4) {
                    if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
                    else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
                } else return (lResult ^ lX8 ^ lY8);
            }

            function F(x, y, z) { return (x & y) | ((~x) & z); }
            function G(x, y, z) { return (x & z) | (y & (~z)); }
            function H(x, y, z) { return (x ^ y ^ z); }
            function I(x, y, z) { return (y ^ (x | (~z))); }

            function FF(a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
            }

            function GG(a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
            }

            function HH(a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
            }

            function II(a, b, c, d, x, s, ac) {
                a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac));
                return addUnsigned(rotateLeft(a, s), b);
            }

            function convertToWordArray(string) {
                var lWordCount;
                var lMessageLength = string.length;
                var lNumberOfWords_temp1 = lMessageLength + 8;
                var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
                var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
                var lWordArray = Array(lNumberOfWords - 1);
                var lBytePosition = 0;
                var lByteCount = 0;
                while (lByteCount < lMessageLength) {
                    lWordCount = (lByteCount - (lByteCount % 4)) / 4;
                    lBytePosition = (lByteCount % 4) * 8;
                    lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
                    lByteCount++;
                }
                lWordCount = (lByteCount - (lByteCount % 4)) / 4;
                lBytePosition = (lByteCount % 4) * 8;
                lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
                lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
                lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
                return lWordArray;
            }

            function wordToHex(lValue) {
                var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
                for (lCount = 0; lCount <= 3; lCount++) {
                    lByte = (lValue >>> (lCount * 8)) & 255;
                    WordToHexValue_temp = "0" + lByte.toString(16);
                    WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
                }
                return WordToHexValue;
            }

            var x = Array();
            var k, AA, BB, CC, DD, a, b, c, d;
            var S11 = 7, S12 = 12, S13 = 17, S14 = 22;
            var S21 = 5, S22 = 9, S23 = 14, S24 = 20;
            var S31 = 4, S32 = 11, S33 = 16, S34 = 23;
            var S41 = 6, S42 = 10, S43 = 15, S44 = 21;

            x = convertToWordArray(inputString);

            a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;

            for (k = 0; k < x.length; k += 16) {
                AA = a; BB = b; CC = c; DD = d;
                a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
                d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
                c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
                b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
                a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
                d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
                c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
                b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
                a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
                d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
                c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
                b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
                a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
                d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
                c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
                b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
                a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
                d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
                c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
                b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
                a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
                d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
                c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
                b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
                a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
                d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
                c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
                b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
                a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
                d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
                c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
                b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
                a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
                d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
                c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
                b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
                a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
                d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
                c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
                b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
                a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
                d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
                c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
                b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
                a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
                d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
                c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
                b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
                a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
                d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
                c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
                b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
                a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
                d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
                c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
                b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
                a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
                d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
                c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
                b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
                a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
                d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
                c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
                b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
                a = addUnsigned(a, AA);
                b = addUnsigned(b, BB);
                c = addUnsigned(c, CC);
                d = addUnsigned(d, DD);
            }

            var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
            return temp.toLowerCase();
        }

        // 显示/隐藏APISecret
        document.getElementById('toggle-secret').addEventListener('click', function() {
            const secretInput = document.getElementById('api-secret');
            const icon = this;

            if (secretInput.type === 'password') {
                secretInput.type = 'text';
                icon.classList.remove('fa-eye');
                icon.classList.add('fa-eye-slash');
            } else {
                secretInput.type = 'password';
                icon.classList.remove('fa-eye-slash');
                icon.classList.add('fa-eye');
            }
        });

        // 复制Dataset ID
        document.getElementById('copy-btn').addEventListener('click', function() {
            const datasetId = document.getElementById('dataset-id').textContent;
            navigator.clipboard.writeText(datasetId).then(() => {
                const originalText = this.innerHTML;
                this.innerHTML = '<i class="fas fa-check"></i> 已复制';
                setTimeout(() => {
                    this.innerHTML = originalText;
                }, 2000);
            });
        });

        // 创建数据集
        document.getElementById('create-btn').addEventListener('click', async function() {
            const appId = document.getElementById('app-id').value.trim();
            const apiSecret = document.getElementById('api-secret').value.trim();
            const datasetName = document.getElementById('dataset-name').value.trim();

            // 隐藏错误和结果
            document.getElementById('error-message').style.display = 'none';
            document.getElementById('result-container').style.display = 'none';

            // 验证输入
            if (!appId || !apiSecret) {
                showError('请输入APPID和APISecret');
                return;
            }

            if (!datasetName) {
                showError('请输入数据集名称');
                return;
            }

            // 显示加载动画
            document.getElementById('loading').style.display = 'flex';

            try {
                // 调用API创建数据集
                const datasetId = await createDataset(appId, apiSecret, datasetName);

                // 显示结果
                document.getElementById('dataset-id').textContent = datasetId;
                document.getElementById('code-dataset-id').textContent = datasetId;
                document.getElementById('timestamp').textContent = '创建时间: ' + new Date().toLocaleString();
                document.getElementById('result-container').style.display = 'block';
            } catch (error) {
                showError(`创建数据集失败: ${error.message}`);
            } finally {
                // 隐藏加载动画
                document.getElementById('loading').style.display = 'none';
            }
        });

        // 创建数据集函数
        async function createDataset(appId, apiSecret, datasetName) {
            const timestamp = Math.floor(Date.now() / 1000);
            const signature = await getSignature(appId, timestamp, apiSecret);

            if (!signature) {
                throw new Error('生成签名失败');
            }

            // 构建请求头 - 注意：不要设置Content-Type，浏览器会自动设置
            const headers = {
                "Accept": "application/json",
                "appId": appId,
                "timestamp": timestamp.toString(),
                "signature": signature
            };

            // 构建表单数据
            const formData = new FormData();
            formData.append("name", datasetName);

            try {
                const response = await fetch('https://chatdoc.xfyun.cn/openapi/v1/dataset/create', {
                    method: 'PUT',
                    headers: headers,
                    body: formData
                });

                if (!response.ok) {
                    const errorText = await response.text();
                    throw new Error(`HTTP错误: ${response.status}, 响应: ${errorText}`);
                }

                const data = await response.json();

                if (data.code === 0) {
                    return data.data;
                } else {
                    throw new Error(data.desc || '未知错误');
                }
            } catch (error) {
                console.error('API调用失败:', error);
                throw new Error(error);
            }
        }

        // 生成签名
        async function getSignature(appId, timestamp, apiSecret) {
            try {
                const authText = appId + timestamp;
                const authMd5 = md5(authText);

                // 计算HMAC-SHA1签名
                const signature = await hmacSha1(apiSecret, authMd5);
                return signature;
            } catch (error) {
                console.error('生成签名失败:', error);
                return null;
            }
        }

        // HMAC-SHA1函数实现
        async function hmacSha1(key, message) {
            const encoder = new TextEncoder();

            // 导入密钥
            const cryptoKey = await crypto.subtle.importKey(
                'raw',
                encoder.encode(key),
                { name: 'HMAC', hash: 'SHA-1' },
                false,
                ['sign']
            );

            // 计算HMAC
            const signature = await crypto.subtle.sign(
                'HMAC',
                cryptoKey,
                encoder.encode(message)
            );

            // 将结果转换为Base64字符串
            const signatureArray = Array.from(new Uint8Array(signature));
            const signatureBase64 = btoa(String.fromCharCode(...signatureArray));

            return signatureBase64;
        }

        // 显示错误信息
        function showError(message) {
            const errorElement = document.getElementById('error-message');
            errorElement.textContent = message;
            errorElement.style.display = 'block';
        }
    </script>
</body>
</html>